/**
 * 
 */
package com.goldentrail.dataobject;

import java.util.ArrayList;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Contains functions for converting goldentrail data objects into a JSON array
 * for use in JIT
 * 
 * @author mikeagun
 * 
 */
public class jit {
	/**
	 * Converts the Invocation list representation of a trace graph to the JIT
	 * graph structure representation
	 * 
	 * @param invocs
	 *            the invocation list containing the graph to be converted
	 * @return JSONArray containing all nodes in JIT
	 */
	public static JSONArray getJITJSONfromInvocs(ArrayList<Invocation> invocs) {
		ArrayList<JSONObject> workingArray = new ArrayList<JSONObject>();
		

		for (Invocation invoc : invocs) {
			JSONObject node = createNode(invoc);
			workingArray.add(node);
			try {
				// TODO: decide whether id should be invocId (which might
				// possibly have dup's), or URL (which only works for graphs
				// extracted from the db)

				if (invoc.getInputData() != null) {
					if (invoc.getInputData().size() > 0) {
						for (String dependencyId : invoc.getInputData()
								.keySet()) {
							JSONObject dataNode = findNode(workingArray, dependencyId);
							if (dataNode == null) {
								dataNode = createNode(invoc.getInputData().get(
										dependencyId));
								workingArray.add(dataNode);
							}
							node.accumulate("adjacencies", dependencyId);
						}
					}
				}
				if (invoc.getOutputData() != null) {
					if (invoc.getOutputData().size() > 0) {
						for (String dependentId : invoc.getOutputData()
								.keySet()) {
							JSONObject dataNode = findNode(workingArray, dependentId);
							if (dataNode == null) {
								dataNode = createNode(invoc.getOutputData()
										.get(dependentId));
								workingArray.add(dataNode);
							}
							dataNode.accumulate("adjacencies",
									node.getString("id"));
						}
					}
				}
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		// add the root node so we can display as space tree
		JSONArray nodes = new JSONArray();
		nodes.put(createRoot(workingArray));
		for(JSONObject obj : workingArray) {
			nodes.put(obj);
		}
		System.out.println("JIT Node Array:" + nodes);

		return nodes;
	}

	/**
	 * create a root node that has all the rightmost nodes of the graph as
	 * dependency (so we can display it as a single root tree)
	 * 
	 * @param array
	 *            the array of jit nodes representing the graph
	 * @return the jit root node that was created
	 */
	/*private static JSONObject createRoot(JSONArray array) {
		JSONObject rootNode = createNode("root", "root", "rectangle");
		ArrayList<String> dependencyIds = new ArrayList<String>();
		try {
			// first find all the nodes that are not rightmost (are a
			// dependency)
			for (int i = 0; i < array.length(); i++) {
				JSONArray deps = array.getJSONObject(i).getJSONArray(
						"adjacencies");

				for (int depIndex = 0; depIndex < deps.length(); depIndex++) {
					String id = deps.getString(depIndex);
					if (!dependencyIds.contains(id))
						dependencyIds.add(id);
				}

			}

			// now find all the nodes that are not-not rightmost (are rightmost)
			// and add them as a dependency to the root node
			for (int i = 0; i < array.length(); i++) {
				String id = array.getJSONObject(i).getString("id");
				if (!dependencyIds.contains(id))
					rootNode.accumulate("adjacencies", id);
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return rootNode;
	}*/

	/**
	 * create a root node that has all the rightmost nodes of the graph as
	 * dependency (so we can display it as a single root tree)
	 * 
	 * @param array
	 *            the array of jit nodes representing the graph
	 * @return the jit root node that was created
	 */
	private static JSONObject createRoot(ArrayList<JSONObject> array) {
		JSONObject rootNode = createNode("root", "root", "rectangle");
		ArrayList<String> dependencyIds = new ArrayList<String>();
		try {
			// first find all the nodes that are not rightmost (are a
			// dependency)
			for (int i = 0; i < array.size(); i++) {
				JSONArray deps = array.get(i).getJSONArray("adjacencies");

				for (int depIndex = 0; depIndex < deps.length(); depIndex++) {
					String id = deps.getString(depIndex);
					if (!dependencyIds.contains(id))
						dependencyIds.add(id);
				}

			}

			// now find all the nodes that are not-not rightmost (are rightmost)
			// and add them as a dependency to the root node
			for (int i = 0; i < array.size(); i++) {
				String id = array.get(i).getString("id");
				if (!dependencyIds.contains(id))
					rootNode.accumulate("adjacencies", id);
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return rootNode;
	}

	/**
	 * Finds a JIT node in a JSON Array, if it exists
	 * 
	 * @param array
	 *            the JSON Array to search in
	 * @param id
	 *            the id of the node to find
	 * @return the node if found, else null
	 */
	/*
	 * private static JSONObject findNode(JSONArray array, String id) { try {
	 * for (int i = 0; i < array.length(); i++) { JSONObject obj =
	 * array.getJSONObject(i); if (obj.getString("id").equals(id)) return obj; }
	 * } catch (JSONException e) { // TODO Auto-generated catch block
	 * e.printStackTrace(); } return null; }
	 */

	/**
	 * Finds a JIT node in an ArrayList, if it exists
	 * 
	 * @param array
	 *            the ArrayList to search
	 * @param id
	 *            the id of the node to find
	 * @return the node if found, else null
	 */
	private static JSONObject findNode(ArrayList<JSONObject> array, String id) {
		try {
			for (JSONObject obj : array) {
				if (obj.getString("id").equals(id))
					return obj;
			}
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Creates a JSON Object rep. of a JIT node for an Invocation
	 * 
	 * @param invoc
	 *            the Invocation to generate a node for
	 * @return the node created
	 */
	private static JSONObject createNode(Invocation invoc) {
		return createNode(invoc.getInvocationId(), invoc.getInvocationId(),
				"rectangle");
	}

	/**
	 * Creates a JSON Object rep. of a JIT node for an DataArtifact
	 * 
	 * @param data
	 *            the DataArtifact to generate a node for
	 * @return the node created
	 */
	private static JSONObject createNode(DataArtifact data) {
		return createNode(data.getDataArtifactId(), data.getDataArtifactId(),
				"circle");
	}

	/**
	 * Creates a JSON Object rep. of a JIT node
	 * 
	 * @param id
	 *            id to give the node
	 * @param name
	 *            name of the jit node
	 * @param type
	 *            type to put in the data section of the node
	 * @return the node created
	 */
	private static JSONObject createNode(String id, String name, String type) {
		JSONObject json = new JSONObject();

		try {
			json.put("id", id);
			json.put("name", name);
			JSONObject datadata = new JSONObject();
			datadata.put("$type", type);
			json.put("data", datadata);
			// TODO: find out if empty arrays are needed when no adjacencies
			json.put("adjacencies", new JSONArray());
		} catch (JSONException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return json;
	}
}
